package com.yc.anno;

import com.yc.vote.entity.TpItems;
import com.yc.vote.mapper.TpItemsMapper;
import org.apache.ibatis.annotations.*;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class SqlSession {

    public static void main(String[] args) {
        SqlSession session = new SqlSession();
        TpItemsMapper mapper = session.getMapper(TpItemsMapper.class);
        System.out.println("====================");
        mapper.insert("abc", 100);
        System.out.println("====================");
        mapper.selectByVid("100");

    }

    public <T> T getMapper(Class<T> cls) {
        // JDK 动态代理技术 => 代理模式
        return (T) Proxy.newProxyInstance(
                // 类加载器
                cls.getClassLoader(),
                // 类实现的接口数组
                new Class<?>[]{cls},
                // 方法拦截
                new InvocationHandler() {
                    @Override
                    public Object invoke(
                            // 代理对象
                            Object proxy,
                            // 方法对象
                            Method method,
                            // 参数数组
                            Object[] args) throws Throwable {
                        System.out.println("proxy = " + proxy.getClass());
                        System.out.println("method = " + method);
                        System.out.println("Arrays.toString(args) = " + Arrays.toString(args));

                        Select select = method.getAnnotation(Select.class);
                        Delete delete = method.getAnnotation(Delete.class);
                        Update update = method.getAnnotation(Update.class);
                        Insert insert = method.getAnnotation(Insert.class);
                        String sql = null;
                        if (select != null) {
                            sql = select.value()[0];
                        } else if (delete != null) {
                            sql = delete.value()[0];
                        } else if (update != null) {
                            sql = update.value()[0];
                        } else if (insert != null) {
                            sql = insert.value()[0];
                        } else {
                            throw new RuntimeException("该方法不是 SQL 方法!");
                        }
                        System.out.println("sql = " + sql);
                        // 提取参数
                        List<String> paramNames = new ArrayList<>();
                        int index = 0;
                        while (  ( index = sql.indexOf("#{",index) ) > 0 ) {
                            int endIndex = sql.indexOf("}", index);
                            String paramName = sql.substring(index + 2, endIndex);
                            paramNames.add(paramName);
                            // 查找下一个参数
                            index = endIndex;
                        }
                        System.out.println("paramNames = " + paramNames);
                        // 将 mybatis 的命名参数 转换成 ?
                        sql = sql.replaceAll("#\\{[\\w\\s]+}", "?");
                        System.out.println("sql = " + sql);
                        // 获取参数值
                        List<Object> paramValues = new ArrayList<>();

                        // 单参数: 基本数据类型 或 字符串
                        if(method.getParameterCount() == 1 ){
                            Parameter parameter = method.getParameters()[0];
                            // isPrimitive基本数据类 int long char ...
                            // Integer
                            if(parameter.getClass().isPrimitive() ||
                                    parameter.getClass().isAssignableFrom(String.class) ||
                                    parameter.getClass().isAssignableFrom(Integer.class)  ||
                                    parameter.getClass().isAssignableFrom(Long.class)  ||
                                    parameter.getClass().isAssignableFrom(Double.class) ) {

                            }
                            for (String paramName : paramNames) {
                                paramValues.add(args[0]);
                            }
                        }
                        // 多参数: 标注 @Param
                        if(method.getParameterCount()>1) {//  或者是 实体对象 map集合
                            Parameter[] parameters = method.getParameters();
                            for (String paramName : paramNames) {
                                for (int i = 0; i < parameters.length; i++) {
                                    Param param = parameters[i].getAnnotation(Param.class);
                                    if (param.value().equals(paramName)){
                                        paramValues.add(args[i]);
                                    }
                                }
                            }
                        }

                        System.out.println("paramValues = " + paramValues);

                        // 参数: 实体对象 => 反射 =>属性名=>属性值=>参数数组

                        // 函数返回值
                        System.out.println("method.getReturnType().getTypeName() = " + method.getReturnType().getTypeName());

                        return null;
                    }
                });
    }
}
